package net.helix.ui.panels.timeline;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.util.ArrayList;

import javax.swing.JPanel;

import net.helix.core.transform.TransformDimension;
import net.helix.engine.Engine;
import net.helix.engine.timeline.layer.TimelineLayer;
import net.helix.engine.timeline.layer.TimelineLayerButton;
import net.helix.engine.timeline.layer.TimelineLayerType;
import net.helix.ui.UIImages;

public class TimelineNamesPane extends JPanel {
	private static final long serialVersionUID = 1L;
	
	public int scrollY;
	
	private int mouseX = Integer.MIN_VALUE;
	private int mouseY = Integer.MIN_VALUE;
	private boolean clicked = false;
	private boolean mousePressed = false;
	private boolean mouseDown = false;
	private boolean mouseReleased = false;
	private boolean mouseLeft = false;
	private boolean dragged = false;
	private boolean doubleClick = false;
	
	private boolean draggingCurrentSelected = false;
	
	private Engine engine;
	private TimelinePane timelinePane;
	
	private TimelineLayerButton currentDraggingLayerButton;
	
	//int drawDraggingSplitterCompare = -1;
	
	public TimelineNamesPane(Engine engine, TimelinePane timelinePane){
		super();
		this.engine = engine;
		this.timelinePane = timelinePane;
		
		
		this.addFocusListener(new FocusListener(){

			@Override
			public void focusGained(FocusEvent arg0) {
				repaint();
			}
			@Override
			public void focusLost(FocusEvent arg0) {
				repaint();
			}
		});
		/*
		this.addHierarchyListener(new HierarchyListener(){
			@Override
			public void hierarchyChanged(HierarchyEvent arg0) {
				
			}
			
		});
		*/
		/*
		this.addHierarchyBoundsListener(new HierarchyBoundsListener(){

			@Override
			public void ancestorMoved(HierarchyEvent arg0) {
				
			}

			@Override
			public void ancestorResized(HierarchyEvent arg0) {
			}
			
		});
		*/
		this.addKeyListener(new KeyListener(){

			@Override
			public void keyPressed(KeyEvent arg0) {
			}

			@Override
			public void keyReleased(KeyEvent arg0) {
			}

			@Override
			public void keyTyped(KeyEvent arg0) {
			}
			
		});
		
		this.addMouseListener(new MouseListener(){

			@Override
			public void mouseClicked(MouseEvent arg0) {
				if(arg0.getClickCount() > 0 && arg0.getClickCount() % 2 == 0){
					doubleClick = true;
				}
				mouseX  = arg0.getX();
				mouseY  = arg0.getY();
				clicked = true;
				repaint();
			}

			@Override
			public void mouseEntered(MouseEvent arg0) {
				
			}

			@Override
			public void mouseExited(MouseEvent arg0) {
				mouseX = Integer.MIN_VALUE;
				mouseY = Integer.MIN_VALUE;
				mouseLeft = true;
				repaint();
			}

			@Override
			public void mousePressed(MouseEvent arg0) {
				mouseDown = true;
				mousePressed = true;
				mouseX  = arg0.getX();
				mouseY  = arg0.getY();
				repaint();
				grabFocus();
			}

			@Override
			public void mouseReleased(MouseEvent arg0) {
				mouseDown = false;
				mouseReleased = true;
				mouseX  = arg0.getX();
				mouseY  = arg0.getY();
				repaint();
			}
			
		});
		
		this.addMouseMotionListener(new MouseMotionListener(){

			@Override
			public void mouseDragged(MouseEvent arg0) {
				mouseX = arg0.getX();
				mouseY = arg0.getY();
				dragged = true;
				repaint();
			}
			@Override
			public void mouseMoved(MouseEvent arg0) {
				mouseX = arg0.getX();
				mouseY = arg0.getY();
				repaint();
			}
			
		});
		
		this.addMouseWheelListener(new MouseWheelListener(){

			@Override
			public void mouseWheelMoved(MouseWheelEvent arg0) {
				
			}
			
		});
		/*
		this.addComponentListener(new ComponentListener(){
			@Override
			public void componentHidden(ComponentEvent arg0) {
				
			}

			@Override
			public void componentMoved(ComponentEvent arg0) {
				
			}

			@Override
			public void componentResized(ComponentEvent arg0) {
				//paint(getGraphics());
				//update(getGraphics());
			}
			@Override
			public void componentShown(ComponentEvent arg0) {
				
			}
			
			
		});
		*/
		
	}
	@Override
	protected void paintComponent(Graphics g) {
		super.paintComponent(g);
		
		//Graphics2D g2d = (Graphics2D) g;

		Dimension d = this.getSize();
		if(hasFocus()){
			g.setColor(new Color(0xF5F5F5));
		}else{
			g.setColor(new Color(0xEEEEEE));
		}
		
		if(engine.getCurrentSelectedTimeline() == null) return;
		
		g.fillRect(0, 0, d.width, d.height);
		
		g.setFont(new Font("Serif", Font.PLAIN, 12));
		//g.setColor(new Color(0x121212));
		
		int offY;
		
		offY = scrollY%20;
		
		ArrayList<TimelineLayerButton> layerButtons = timelinePane.getListOfLayers();
		
		TimelineLayerButton dragingLayerTo = null;
		
		// initial loop for clicking on layers
		
		int layerIndex = (scrollY - offY)/20;
		for(int y=-offY;y<d.height;y+=20){
			TimelineLayer layer = null;
			TimelineLayerButton layerButton = null;
			if(layerIndex >= 0 && layerIndex < layerButtons.size()){
				layerButton = layerButtons.get(layerIndex);
			}
			if(layerButton != null){
				layer = layerButton.layer;
				if(mouseY >= y && mouseY < y+20){
					if(clicked){
						//engine.setCurrentSelectedLayer(layer);
						engine.getCurrentSelectedTimeline().setCurrentSelectedLayer(layer);
					}
					if(doubleClick){
						layer.showChildren = !layer.showChildren;
						timelinePane.reloadLayersList();
						timelinePane.UpdateTimelineScrollbars();
					}
					
					if(mousePressed){
						
						currentDraggingLayerButton = layerButton;
					}
					if(dragged && mouseDown){
						draggingCurrentSelected = true;
					}
					/*
					if(currentDraggingLayer == layer){
						drawDraggingSplitterCompare = y;
					}
					*/
				}
			}
			layerIndex++;
		}
		
		
		
		
		
		DragDirection draggingLayerDirection = DragDirection.UP;
		
		// loop through ALL buttons for interactivity... (looping through off screen ones as well)
		int lastY = 0;
		
		int layerButtonsLength = layerButtons.size();
		for(int i=0;i<layerButtonsLength;i++){
			TimelineLayerButton layerButton = layerButtons.get(i);
			
			int y = layerButton.position*20 - scrollY;
			lastY = y;
			
			if(mouseY >= y && mouseY < y+20){
				layerButton.highlighted = true;
			}else{
				layerButton.highlighted = false;
			}
			
			if(engine.getCurrentSelectedTimeline().getCurrentSelectedLayer() == layerButton.layer){
				layerButton.selected = true;
			}else{
				layerButton.selected = false;
			}
			
			if(currentDraggingLayerButton == layerButton){
				layerButton.dragging = true;
			}else{
				layerButton.dragging = false;
			}
			
			
			if(draggingCurrentSelected && mouseY >= y && mouseY < y+20){
				//if(y > drawDraggingSplitterCompare){
				dragingLayerTo = layerButton;
				
				
				
				if(mouseY < y+10){
					draggingLayerDirection = DragDirection.UP;
				}else{
					draggingLayerDirection = DragDirection.DOWN;
				}
				
				if(layerButton.layer.type == TimelineLayerType.CAMERA || layerButton.layer.type == TimelineLayerType.FOLDER){
					if(mouseY > y+7 && mouseY < y+18){
						draggingLayerDirection = DragDirection.IN;
					}
					
				}
				
				//}
			}
			
			
		}
		if(draggingCurrentSelected && dragingLayerTo == null){
			if(mouseY - scrollY <= 0 && layerButtonsLength > 0){
				dragingLayerTo = layerButtons.get(0);
				draggingLayerDirection = DragDirection.UP;
			}
			if(mouseY - scrollY >= lastY){
				dragingLayerTo = layerButtons.get(layerButtonsLength-1);
				draggingLayerDirection = DragDirection.BOTTOM;
			}
			
		}
		
		
		
		// loop to render all of the layers
		layerIndex = (scrollY - offY)/20;
		for(int y=-offY;y<d.height;y+=20){
			TimelineLayerButton layerButton = null;
			TimelineLayer layer = null;
			if(layerIndex >= 0 && layerIndex < layerButtons.size()){
				layerButton = layerButtons.get(layerIndex);
			}
			if(layerButton != null){
				layer = layerButton.layer;
				
				Color bgColor = null;
				
				// hasFocus();
				if(layerButton.dragging == true){
					if(draggingCurrentSelected == false){
						if(layerButton.highlighted){
							bgColor = new Color(0x8181FF);
						}else{
							bgColor = new Color(0x5151FF);
						}
					}else{
						bgColor = new Color(0x81DDDD);
					}
				}else if(layerButton.highlighted){
					if(layerButton.selected){
						bgColor = new Color(0xFFFFFF);
					}else{
						bgColor = new Color(0xF0F0F0);
					}
				}else{
					if(layerButton.selected){
						bgColor = new Color(0xF9F9F9);
					}else{
						bgColor = new Color(0xE0E0E0);
					}
				}
				
				
				g.setColor(bgColor);
				g.fillRect(0, y, d.width, 19);
				
				if(layer.dimension == TransformDimension.THREE){
					// draw graphic to show it as a 3d layer
					g.drawImage(UIImages.timelineIcons5, layerButton.depth*12, y, null);
				}else{
					// show as 2d layer
					g.setColor(new Color(0x121212));
					g.drawRect(layerButton.depth*12 + 5, y + 4, 8, 8);
					
					g.setColor(new Color(0x737373));
					g.fillRect(layerButton.depth*12 + 6, y + 5, 7, 7);
				}
				
				if(layer.type == TimelineLayerType.CAMERA){
					g.drawImage(UIImages.timelineIcons3, layerButton.depth*12 + 16, y, null);
				}
				
				g.setColor(new Color(0x121212));
				g.drawString(layer.name, layerButton.depth*12 + 32, y+16);
				
				g.setColor(new Color(0x121212));
				g.drawLine(0, y, d.width, y);
				
				g.setColor(new Color(0xD2D2D2));
				g.drawLine(0, y+19, d.width, y+19);
				
				
				g.setColor(bgColor);
				g.fillRect(d.width-16*2, y+1, 16*2, 18);
				/*
				g.drawImage(UIImages.timelineIcons5, d.width-16, y, null);
				g.drawImage(UIImages.timelineIcons4, d.width-16*2, y, null);
				g.drawImage(UIImages.timelineIcons3, d.width-16*3, y, null);
				*/
				g.drawImage(UIImages.timelineIcons2, d.width-16*1, y, null);
				g.drawImage(UIImages.timelineIcons1, d.width-16*2, y, null);
			}
			layerIndex++;
		}
		/*
		if(draggingCurrentSelected && drawDraggingSplitter == -1){
			if(mouseY < drawDraggingSplitterCompare){
				drawDraggingSplitter = offY;
			}else{
				drawDraggingSplitter = lastY+19;
			}
		}
		*/
		if(dragingLayerTo != null){
			g.setColor(new Color(0x3D3DEF));
			if(draggingLayerDirection == DragDirection.BOTTOM){
				// Bottom is a special case where it places the layer at the root
				// hierarchy, but at the bottom.
				g.fillRect(0, dragingLayerTo.position*20-scrollY-2+20, d.width, 4);
			}else if(draggingLayerDirection == DragDirection.IN){
				// places the layer right AFTER the other frame that is selected
				g.fillRect(dragingLayerTo.depth*16+16, dragingLayerTo.position*20-scrollY-2+15, d.width, 4);
			}else if(draggingLayerDirection == DragDirection.DOWN){
				// places the layer right AFTER the other frame that is selected
				g.fillRect(dragingLayerTo.depth*16, dragingLayerTo.position*20-scrollY-2+20, d.width, 4);
			}else{
				// places the layer right BEFORE the other frame that is selected
				g.fillRect(dragingLayerTo.depth*16, dragingLayerTo.position*20-scrollY-2, d.width, 4);
			}
		}
		
		if(clicked || mouseReleased){
			draggingCurrentSelected = false;
			if(currentDraggingLayerButton != null && dragingLayerTo != null){
				if(currentDraggingLayerButton.layer == dragingLayerTo.layer && draggingLayerDirection != DragDirection.BOTTOM){
					System.out.println("Not moving layer");
				}else if(currentDraggingLayerButton.layer.containsChild(dragingLayerTo.layer)){
					System.out.println("Can't drag to be child of self.");
				}else{
					
					if(currentDraggingLayerButton.parentLayer != null){
						currentDraggingLayerButton.parentLayer.removeChildLayer(currentDraggingLayerButton.layer);
						
					}else{
						engine.getCurrentSelectedTimeline().removeLayer(currentDraggingLayerButton.layer);
					}
					
					/*
					 * If this is the root timeline, then layers can only be placed under
					 * camera layers of the same dimension. Otherwise, if this is a 2d or 3d clip, you can place the layers
					 * anywhere. You cannot add cameras to a clip.
					 */
					
					if(dragingLayerTo.parentLayer == null){
						
					}
					
					
					System.out.println("Dragging "+currentDraggingLayerButton.layer.name + " to:");
					if(draggingLayerDirection == DragDirection.BOTTOM){
						System.out.println("Placing layer at bottom");
						engine.getCurrentSelectedTimeline().addLayerToEnd(currentDraggingLayerButton.layer);
					}else if(draggingLayerDirection == DragDirection.IN){
						dragingLayerTo.layer.AddChildLayer(currentDraggingLayerButton.layer);
					}else if(draggingLayerDirection == DragDirection.DOWN){
						System.out.println("Placing after "+dragingLayerTo.layer.name);
						if(dragingLayerTo.parentLayer == null){
							engine.getCurrentSelectedTimeline().addLayerAfter(currentDraggingLayerButton.layer, dragingLayerTo.layer);
						}else{
							dragingLayerTo.parentLayer.addLayerAfter(currentDraggingLayerButton.layer, dragingLayerTo.layer);
						}
					}else{
						System.out.println("Placing before "+dragingLayerTo.layer.name);
						if(dragingLayerTo.parentLayer != null){
							dragingLayerTo.parentLayer.addLayerBefore(currentDraggingLayerButton.layer, dragingLayerTo.layer);
						}else{
							engine.getCurrentSelectedTimeline().addLayerBefore(currentDraggingLayerButton.layer, dragingLayerTo.layer);
						}
					}
					timelinePane.reloadLayersList();
					timelinePane.repaintNamesAndFrames();
				}
				
			}
			currentDraggingLayerButton = null;
			this.repaint();
		}
		clicked = false;
		mouseReleased = false;
		mousePressed = false;
		mouseLeft = false;
		dragged = false;
		doubleClick = false;
	}
	/*
	private void doPaint(){
		if(getBufferStrategy() == null) createBufferStrategy(2);
		
		
		BufferStrategy strategy = getBufferStrategy();
		Graphics g = strategy.getDrawGraphics();
		
		Graphics2D g2d = (Graphics2D) g;
		
		Dimension d = this.getSize();
			g.setColor(Color.red);
		g.fillOval(0, 0, d.width, d.height);
		
		// paint to graphics object here
		g.dispose();
		// flush the buffer to the main graphics
		strategy.show();
	}
	*/
	enum DragDirection{
		UP, DOWN, BOTTOM, IN;
	}
	
}
